package miage.rest.form;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import miage.rest.validation.Validator;
import miage.rest.validation.ValidatableForm;
import org.restlet.representation.Representation;

/**
 * Classe de formulaire basé sur la classe de formulaire de restlet qui ajoute la possibilité de
 * valider les paramètres
 *
 * @author Schwartz Michaël
 */
public class Form extends org.restlet.data.Form implements ValidatableForm {

	private List<String> messages;
	private Map<String, List<Validator<String>>> validatorsPerParamaterName;

	public Form() {
		super();

		this.validatorsPerParamaterName = new HashMap<String, List<Validator<String>>>();
	}

	public Form(Representation entity) {
		super(entity);

		this.validatorsPerParamaterName = new HashMap<String, List<Validator<String>>>();
	}

	/**
	 * Ajoute un validator pour le parametre donné
	 * 
	 * @require parameterName != null
	 *
	 * @param parameterName
	 * @param validator
	 * @throws NullPointerException
	 * @throws UnsupportedOperationException
	 */
	public void addValidator(String parameterName, Validator<String> validator) {
        assert parameterName != null;


		if (!validatorsPerParamaterName.containsKey(parameterName)) {
			validatorsPerParamaterName.put(parameterName, new ArrayList<Validator<String>>());
		}
		
		validatorsPerParamaterName.get(parameterName).add(validator);
		
	}


	/**
	 * Ajoute les validator passés en paramètre au paramètre donné
	 *
	 * @require parameterName != null;
	 *
	 * @param parameterName
	 * @param validators
	 */
	public void addValidators(String parameterName, Validator<String>... validators) {
		assert parameterName != null;

		for(Validator<String> validator : validators) {
			addValidator(parameterName, validator);
		}
	}

	/**
	 * Enlève un validator pour le parameterName
	 * Ne fait rien si le validator n'existait pas
	 *
	 * @require parameterName != null
	 *
	 * @param parameterName
	 * @param validator
	 */
	public void removeValidator(String parameterName, Validator<String> validator) {
		assert parameterName != null;

		if (this.validatorsPerParamaterName.containsKey(parameterName)) {
			this.validatorsPerParamaterName.get(parameterName).remove(validator);
		}
	}


	/**
	 * Enlève tous les validator pour le parameterName
	 *
	 * @require parameterName != null
	 *
	 * @param parameterName
	 */
	public void clearValidators(String parameterName) {
		assert parameterName != null;

		if(this.validatorsPerParamaterName.containsKey(parameterName)) {
			this.validatorsPerParamaterName.get(parameterName).clear();
		}
	}

	public void setValidators(String parameterName, List<Validator<String>> validators) {
		assert parameterName != null;

		this.validatorsPerParamaterName.put(parameterName,validators);
		
	}

	/**
	 * Retourne une liste non modifiable des validators pour ce champs
	 *
	 * @require parameterName != null
	 *
	 * @param parameterName
	 * @return
	 */
	public List<Validator<String>> getValidators(String parameterName) {
		assert parameterName != null;

		List<Validator<String>> validators;

		if(this.validatorsPerParamaterName.containsKey(parameterName)){
			validators = this.validatorsPerParamaterName.get(parameterName);
		} else {
			validators = Collections.emptyList();
		}
		
		return validators;
	}


	/**
	 * Retourne la liste des messages d'erreur ou une liste vide si il n'y a
	 * pas de messages
	 * 
	 * @return
	 */
	public List<String> getMessages() {
		List<String> msg;
		if (messages != null) {
			msg = Collections.unmodifiableList(messages);
		} else {
			msg = Collections.emptyList();
		}

		return msg;
	}

	
	private void addMessages(List<String> msgs) {
		if (messages == null) {
			messages = new ArrayList<String>();
		}

		messages.addAll(msgs);
	}

	private void clearMessages() {
		if (messages != null) {
			messages.clear();
		}
	}


	public boolean isValid() {
		boolean result = true;
		this.clearMessages();
		for (String parameterName : this.validatorsPerParamaterName.keySet()) {
			for (Validator<String> validator : this.validatorsPerParamaterName.get(parameterName)) {
				result = result && validator.isValid(this.getFirstValue(parameterName));
				addMessages(validator.getMessages());
				validator.clearMessages();
			}
		}
		return result;
	}

}
